package com.erbantou.filemanage.service.impl;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.OSSObjectSummary;
import com.aliyun.oss.model.ObjectListing;
import com.aliyun.oss.model.ObjectMetadata;
import com.erbantou.filemanage.service.StorageService;
import io.minio.messages.Part;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * AliyunOssStorageService 提供了与阿里云 OSS 对象存储服务交互的方法
 */
@Service
@ConditionalOnProperty(name = "custom.storage.service", havingValue = "AliyunOssStorageService")
public class AliyunOssStorageService implements StorageService {

    // 阿里云 OSS 配置参数
    @Value("${aliyun.oss.endpoint}")
    private String endpoint;
    @Value("${aliyun.oss.access-key-id}")
    private String accessKeyId;
    @Value("${aliyun.oss.access-key-secret}")
    private String accessKeySecret;
    @Value("${aliyun.oss.bucket-name}")
    private String bucketName;

    /**
     * 获取 OSS 客户端实例
     *
     * @return OSSClient 对象
     */
    private OSS getOssClient() {
        return new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
    }

    @Override
    public void uploadFile(String objectName, MultipartFile multipartFile) throws Exception {
        OSS ossClient = getOssClient();
        try {
            ossClient.putObject(bucketName, objectName, multipartFile.getInputStream());
        } finally {
            ossClient.shutdown();
        }
    }

    /**
     * 上传文件的部分数据到对象存储。
     *
     * @param objectName 上传对象的名称，包括路径。例如："folder/file.txt"
     * @param buffer     包含要上传的数据的字节数组。
     * @param bytesRead  缓冲区中实际读取的字节数。
     * @throws Exception 如果在上传过程中发生错误。
     */
    public void uploadFilePart(String objectName, byte[] buffer, int bytesRead) throws Exception {
        // 获取 OSS 客户端实例
        OSS ossClient = getOssClient();
        try (InputStream inputStream = new ByteArrayInputStream(buffer, 0, bytesRead)) {
            // 创建对象元数据
            ObjectMetadata metadata = new ObjectMetadata();
            // 设置内容长度
            metadata.setContentLength(bytesRead);

            // 上传对象到指定的存储桶
            ossClient.putObject(bucketName, objectName, inputStream, metadata);
        } finally {
            // 关闭 OSS 客户端
            ossClient.shutdown();
        }
    }

    @Override
    public List<String> listObjects() throws Exception {
        return listObjects("", false);
    }

    @Override
    public List<String> listObjects(boolean recursive) throws Exception {
        return listObjects("", recursive);
    }

    @Override
    public List<String> listObjects(String prefix) throws Exception {
        return listObjects(prefix, false);
    }

    @Override
    public List<String> listObjects(String prefix, boolean recursive) throws Exception {
        OSS ossClient = getOssClient();
        List<String> objectNames = new ArrayList<>();
        try {
            ObjectListing objectListing = ossClient.listObjects(bucketName, prefix);
            for (OSSObjectSummary objectSummary : objectListing.getObjectSummaries()) {
                objectNames.add(objectSummary.getKey());
            }
        } finally {
            ossClient.shutdown();
        }
        return objectNames;
    }

    @Override
    public InputStream getObject(String objectName) throws Exception {
        OSS ossClient = getOssClient();
        try {
            return ossClient.getObject(bucketName, objectName).getObjectContent();
        } finally {
            ossClient.shutdown();
        }
    }

    @Override
    public void removeObject(String objectName) throws Exception {
        OSS ossClient = getOssClient();
        try {
            ossClient.deleteObject(bucketName, objectName);
        } finally {
            ossClient.shutdown();
        }
    }

    @Override
    public void removeObjects(String objectName) throws Exception {
        OSS ossClient = getOssClient();
        try {
            listObjects(objectName, true).forEach(object -> {
                ossClient.deleteObject(bucketName, object);
            });
        } finally {
            ossClient.shutdown();
        }
    }

    @Override
    public boolean isObjectExist(String objectName) {
        OSS ossClient = getOssClient();
        try {
            ObjectMetadata metadata = ossClient.getObjectMetadata(bucketName, objectName);
            return metadata != null;
        } catch (Exception e) {
            // 判断是否是对象不存在的错误
            if (e instanceof com.aliyun.oss.ClientException ce) {
                if (ce.getErrorCode().equalsIgnoreCase("NoSuchKey")) {
                    return false;
                }
            }
            throw new RuntimeException("Error checking if object exists", e);
        } finally {
            ossClient.shutdown();
        }
    }

    @Override
    public String initMultiPartUpload(String objectName, BufferedInputStream data, int partSize, String contentType) throws Exception {
        return null;
    }

    @Override
    public long uploadFilePart(String objectName, BufferedInputStream data, String contentType, long objectSize, long uploadedSize, int partCount, int partSize, Part[] parts, int partNumber, String uploadId) throws Exception {
        return 0;
    }

    @Override
    public void completeMultipartUpload(String objectName, Part[] parts, String uploadId) throws Exception {

    }

    @Override
    public InputStream getObjectAsZipStream(List<String> objectNames, String prefix) throws IOException {
        return null;
    }
}
